﻿#include "Osgb23DTiles.h"

#include <qfiledialog.h>
#include <QTime>
#include <qmessagebox.h>
#include <qdebug.h>
#include<qstring.h>
#include<qfileinfo.h>
#include<qdir.h>
#include<list>
#include<osg/Notify>
#include"osgb/osgb.h"
#include "osgb/json.hpp"
#include "osgb/OsgbModel.h"
#include "osgb/ThreadPool.h"
#include "osgb/tinyxml2.h"
#include <vector>
#include <fstream>

using json = nlohmann::json;
using namespace tinyxml2;

class  MyNotifyHandler : public osg::NotifyHandler
{
	std::ofstream f1;
public:
	MyNotifyHandler():f1("c:\\me.txt") {
	};
	virtual void notify(osg::NotifySeverity severity, const char *message) {
		f1 << message << std::endl;
	};
};


Osgb23DTiles::Osgb23DTiles(QWidget *parent)
	: QDialog(parent)
{
	ui.setupUi(this);

}

Osgb23DTiles::~Osgb23DTiles()
{
}


std::string & replace_all(std::string & str, const std::string & old_value, const std::string & new_value)
{
	std::string::size_type   pos(0);
	while (true) {
		if ((pos = str.find(old_value, pos)) != std::string::npos) {
			str.replace(pos, old_value.length(), new_value);
			pos += old_value.length();
		}
		else   break;
	}
	return str;
}


std::vector<double> make_tile_box(double box[], int len)
{
	std::vector<double> tile_box;
	tile_box.push_back((box[0] + box[3]) / 2.0);
	tile_box.push_back((box[1] + box[4]) / 2.0);
	tile_box.push_back((box[2] + box[5]) / 2.0);


	tile_box.push_back((box[3] - box[0]) / 2.0);
	tile_box.push_back(0.0);
	tile_box.push_back(0.0);


	tile_box.push_back(0.0);
	tile_box.push_back((box[4] - box[1]) / 2.0);
	tile_box.push_back(0.0);


	tile_box.push_back(0.0);
	tile_box.push_back(0.0);
	tile_box.push_back((box[5] - box[2]) / 2.0);
	return tile_box;
}

void Osgb23DTiles::on_pBtnOpenPath_clicked()
{
	QString file_path = QFileDialog::getExistingDirectory(this,
		QString::fromLocal8Bit("请选择文件路径..."), "./");
	if (file_path.isEmpty())
	{
		return;
	}
	ui.lineEditInputPath->setText(file_path);
}

void Osgb23DTiles::on_pBtnOutputPath_clicked()
{

	QString file_path = QFileDialog::getExistingDirectory(this,
		QString::fromLocal8Bit("请选择文件路径..."), "./");
	if (file_path.isEmpty())
	{
		return;
	}
	ui.lineEditOutPutPath->setText(file_path);
}
MyNotifyHandler notifyHandler;
void Osgb23DTiles::on_pBtnStart_clicked()
{
	osg::setNotifyLevel(osg::NotifySeverity::INFO);

	osg::setNotifyHandler(&notifyHandler);
	ui.progressBar->setValue(0);
	convert_osgb(ui.lineEditInputPath->text().trimmed(), ui.lineEditOutPutPath->text().trimmed());

}

struct reult {
	double box[6];
	Tile  json;
};

std::vector<std::string> split(std::string strtem, char a)
{
	std::vector<std::string> strvec;

	std::string::size_type pos1, pos2;
	pos2 = strtem.find(a);
	pos1 = 0;
	while (std::string::npos != pos2)
	{
		strvec.push_back(strtem.substr(pos1, pos2 - pos1));

		pos1 = pos2 + 1;
		pos2 = strtem.find(a, pos1);
	}
	strvec.push_back(strtem.substr(pos1));
	return strvec;

}

void Osgb23DTiles::convert_osgb(QString osgb_dir, QString tile_dir)
{
	QString data_dir = osgb_dir + "/Data";
	QFileInfo proFileInfo(data_dir);
	if (!proFileInfo.exists())
	{
		QString str("未找到目录:%1");
		str.arg(data_dir);
		QMessageBox information(QMessageBox::Icon::NoIcon, "Title", str, QMessageBox::StandardButton::Yes);
		information.exec();
		return;
	}
	double center_x, center_y = 0;
	QString cxstr = ui.lineEditX->text();
	QString cystr = ui.lineEditY->text();
	if (cxstr.length() > 0)
		center_x = std::stod(cxstr.toStdString());
	if (cystr.length() > 0)
		center_y = std::stod(cystr.toStdString());

	QString metadata_file = osgb_dir += "/metadata.xml";
	QFileInfo metadataFileInfo(metadata_file);
	if (metadataFileInfo.exists())
	{
		XMLDocument doc;
		doc.LoadFile(metadata_file.toLocal8Bit());
		auto element = doc.FirstChildElement("ModelMetadata");
		std::string srs = element->FirstChildElement("SRS")->GetText();
		if (srs.length() > 0) {
			ui.lineEditSRS->setText(QString::fromStdString(srs));
			auto vecsrs = split(srs, ':');
			if (vecsrs.size() > 1) {
				if (vecsrs[0] == "ENU") {
					auto vecenu = split(vecsrs[1], ',');
					if (vecenu.size() > 1) {
						center_x = std::stod(vecenu[0]);
						center_y = std::stod(vecenu[1]);
					}
				}
				else if (vecsrs[0] == "EPSG") {
					int epsg = std::stoi(vecsrs[1]);
					std::string SRSOrigin = element->FirstChildElement("SRSOrigin")->GetText();
					ui.lineEditSRSOrigin->setText(QString::fromStdString(SRSOrigin));
					auto vecxyz = split(SRSOrigin, ',');
					if (vecxyz.size() >= 2) {

						double x = std::stod(vecxyz[1]);
						double  y = std::stod(vecxyz[0]);
						double  z = std::stod(vecxyz[2]);
						double xyz[] = { x,y,z };
						QString path = QApplication::applicationDirPath() + "/gdal_data";
                        //epsg_convert(epsg, xyz, (char*)(path.toStdString().c_str()));
						center_x = xyz[0];
						center_y = xyz[1];
					}
				}
			}
		}
	}
	ui.lineEditX->setText(QString::number(center_x, 'f', 3));
	ui.lineEditY->setText(QString::number(center_y, 'f', 3));
	ui.lineEditZ->setText("0");
	QString out_path = tile_dir + "/Data/";
	QDir outdir(tile_dir);
	outdir.mkdir("Data");
	outdir.cd("Data");
	QDir sogbdir(data_dir);

	//DirectoryInfo[] DirSub = Dir.GetDirectories();

	ui.progressBar->setMaximum(sogbdir.entryInfoList().size() - 2);
	convetThread.setPath(sogbdir, outdir);
	convetThread.setCenter(center_y, center_x);
	QString strmaxlvl = ui.lineEditMaxLvl->text();
	int maxlvl = 100;
	if (strmaxlvl.length() > 0) {
		maxlvl = strmaxlvl.toInt();
	}
	double minh = 0;
	QString strminh = ui.lineEditMinH->text();
	if (strminh.length() > 0) {
		minh = strminh.toDouble();
	}
	convetThread.setMaxlvl(maxlvl);
	convetThread.setMinhight(minh);
	connect(&convetThread, SIGNAL(notify(int)), this, SLOT(updateProgressBarNotify(int)));
	connect(&convetThread, SIGNAL(notifyDone(long)), this, SLOT(updateDone(long)));
	ui.pBtnStart->setEnabled(false);
	ui.textBrowser->setText("");
	convetThread.start();

	//MessageBox.Show("转换完成！");
}

void RunThread::run()
{
    //QTime time;
    //time.start();
	double root_box[] = { -1.0E+38, -1.0E+38, -1.0E+38, 1.0E+38, 1.0E+38, 1.0E+38 };
	int count = 0;
	ThreadPool pool(10);
	std::vector< std::future<reult> > results;

	foreach(QFileInfo f, _inpath.entryInfoList())
	{
		if (f.isFile())
		{
			qDebug() << "File :" << f.fileName();
		}
		else
		{

			if (f.fileName() == "." || f.fileName() == "..")continue;
			qDebug() << "Entry Dir" << f.absoluteFilePath();
			QString osgbfilepath = f.filePath() + "/";
			QString osgbfilename = f.fileName() + ".osgb";
			QString osb_sub = osgbfilepath + osgbfilename;
			QFileInfo fileInfo(osb_sub);
			if (!fileInfo.exists())
			{
				continue;
			}

			_outpath.mkdir(f.fileName());
			QString outpath = _outpath.path() + "/" + f.fileName();
			int tmpmax = maxlvl;
			results.emplace_back(
				pool.enqueue([osgbfilepath, osgbfilename, outpath, tmpmax] {
				reult re;
				re.json = osgb23dtile_path(osgbfilepath.toStdString().c_str(), osgbfilename.toStdString().c_str(), outpath.toStdString().c_str(), re.box, 0, 0, tmpmax);
				return re;
			}));
		}
	}

	// 合并外包矩形，合并输出 json
	TileSet tilejson;

	tilejson.asset.gltfUpAxis = "Z";
	tilejson.asset.version = "1.0";
	tilejson.geometricError = 2000;

	tilejson.root.boundingVolume.box = { 0, 0, 0,0, 0, 0,0, 0,0,0,0 ,0 };
	tilejson.root.geometricError = 2000;

	tilejson.root.transform = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };


	// write the transform
	double root_transform[16];

	transform_c(centerx, centery, minh, root_transform);

	for (int i = 0; i < 16; i++)
	{
		tilejson.root.transform[i] = root_transform[i];
	}

	tilejson.root.children.clear();


	_outpath.cd("..");

	for (auto && result : results)
	{
		auto re = result.get();
		count++;
		notify(count);
		Tile tileObject;
		tileObject.boundingVolume = re.json.boundingVolume;
		tileObject.geometricError = re.json.geometricError;
		tileObject.content.uri = replace_all(re.json.content.uri, "./", "./Data/");
		tileObject.content.uri = replace_all(tileObject.content.uri, ".b3dm", "/tileset.json");
		tilejson.root.children.push_back(tileObject);

		for (int i = 0; i < 3; i++)
			root_box[i] = re.box[i] > root_box[i] ? re.box[i] : root_box[i];
		for (int i = 3; i < 6; i++)
			root_box[i] = re.box[i] < root_box[i] ? re.box[i] : root_box[i];
	}

	auto bbox = make_tile_box(root_box, 6);
	for (int i = 0; i < bbox.size(); i++)
	{
		tilejson.root.boundingVolume.box[i] = bbox[i];
	}


	json js = tilejson;

	std::string out_string = js.dump();
	QFile file(_outpath.path() + "/tileset.json");
	file.open(QIODevice::WriteOnly | QIODevice::Text);
	file.write(QString::fromStdString(out_string).toUtf8());
	file.close();

    //notifyDone(time.elapsed());
}
